using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Provider;
using Nivot.PowerShell.WindowsMobile.Rapi2;

namespace Nivot.PowerShell.WindowsMobile
{
    [CmdletProvider("WindowsMobile", ProviderCapabilities.ShouldProcess)]
    public class WindowsMobileProvider : StoreProviderBase
    {
        public readonly static string ProviderName = "WindowsMobile";
        private IStoreObjectModel m_storeObjectModel;

        /// <summary>
        /// Provides a handle to the runtime object model of the backing store
        /// </summary>
        public override IStoreObjectModel StoreObjectModel
        {
            get
            {
                using (EnterContext())
                {
                    if (this.PSDriveInfo == null)
                    {
                        var exception = new PSArgumentException("Driveless operation not supported.");
                        var record = new ErrorRecord(exception, "NoDrive", ErrorCategory.InvalidArgument, null);
                        ThrowTerminatingError(record);
                    }
                    
                    // ensure path is for this provider
                    Type providerType = this.PSDriveInfo.Provider.ImplementingType;
                    if (providerType != typeof (WindowsMobileProvider))
                    {
                        // use same message as stock providers for consistency.
                        var exception = new PSArgumentException("Source and destination path did not resolve to the same provider.");
                        var record = new ErrorRecord(exception, "DifferingProviderPaths", ErrorCategory.InvalidArgument, null);
                        ThrowTerminatingError(record);
                    }
                    
                    m_storeObjectModel = ((WindowsMobileDriveInfo) this.PSDriveInfo).ObjectModel;
                }
                return m_storeObjectModel;
            }
        }

        protected override void NewItem(string path, string type, object newItem)
        {
            WriteVerbose(String.Format("{0} {1} {2}", path, type, newItem));

            string parentPath = SessionState.Path.ParseParent(path, null);

            using (EnterContext())
            {
                switch (type.ToLower())
                {
                    case "folder":
                    case "directory":
                    case "container":

                        if (IsItemContainer(parentPath))
                        {
                            // TODO: add new folder code
                            if (ShouldProcess(path, "Create folder"))
                            {
                                var folder = this.StoreObjectModel.GetItem(parentPath) as WindowsMobileFolder;
                                if (folder != null)
                                {
                                    folder.CreateFolder(path);
                                }
                                else
                                {
                                    var error =
                                        new ErrorRecord(new PSArgumentException(
                                                            String.Format("Path {0} is not a WindowsMobileFolder.",
                                                                          parentPath), "path"),
                                                        "PathNotFolderType", ErrorCategory.InvalidArgument, parentPath);

                                    ThrowTerminatingError(error);
                                }
                            }
                        }
                        else
                        {
                            var error =
                                new ErrorRecord(new PSArgumentException(
                                                    String.Format("Path {0} is not a container.", parentPath), "path"),
                                                "PathNotContainer", ErrorCategory.InvalidArgument, parentPath);

                            ThrowTerminatingError(error);
                        }
                        // ...
                        break;
                    default:
                        base.NewItem(path, type, newItem);
                        break;
                }
            }
        }

        protected override object NewItemDynamicParameters(string path, string itemTypeName, object newItemValue)
        {
            return base.NewItemDynamicParameters(path, itemTypeName, newItemValue);
        }

        public new WindowsMobileProviderInfo ProviderInfo
        {
            get { return (WindowsMobileProviderInfo) base.ProviderInfo; }
        }

        protected override ProviderInfo Start(ProviderInfo providerInfo)
        {
            return new WindowsMobileProviderInfo(providerInfo);
        }

        protected override void Stop()
        {
            try
            {
                base.Stop();
            }
            finally
            {
                if (this.ProviderInfo != null)
                {
                    ProviderInfo.Dispose();
                }
            }
        }

        protected override Collection<PSDriveInfo> InitializeDefaultDrives()
        {
            Collection<PSDriveInfo> drives = base.InitializeDefaultDrives();

            using (EnterContext())
            {
                WriteDebug("Trying to connect...");
                RemoteDevice device = ProviderInfo.DeviceManager.Devices.FirstConnectedDevice;

                if (device != null)
                {
                    drives = new Collection<PSDriveInfo>();

                    drives.Add(
                        new WindowsMobileDriveInfo("Mobile", this.ProviderInfo, @"\",
                            string.Format("{0} ({1} {2})", device.Name, device.Platform,
                                device.OSVersion), null));
                }
                else
                {
                    // won't get written to warning stream... bug?
                    WriteWarning("No device detected.");
                }
            }

            return drives;
        }
    }
}